package com.odontosis.dao;

import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.apache.poi.hssf.record.formula.functions.Year;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import sun.security.x509.CertificateAlgorithmId;

import com.odontosis.as.OdontosisDataAccessObject;
import com.odontosis.entidade.Paciente;
import com.odontosis.entidade.Pagamento;
import com.odontosis.entidade.Servico;
import com.odontosis.util.HibernateUtil;
import com.odontosis.util.StringUtilsOdontosis;

public class PagamentoDAO extends OdontosisDataAccessObject<Pagamento> {

	@SuppressWarnings("unchecked")
	public Collection<Pagamento> buscarPagamentosPorPeriodo(Date inicio, Date fim , Paciente paciente, String nomePaciente){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(inicio);
		int mesInicio =  calendar.get(Calendar.MONTH) + 1;
		int anoInicio = calendar.get(Calendar.YEAR);
		calendar.setTime(fim);
		int mesFinal =  calendar.get(Calendar.MONTH) + 1;
		int anoFinal = calendar.get(Calendar.YEAR);
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		Criteria criteria = session.createCriteria(Pagamento.class);
		criteria.createAlias("servico", "s");
		criteria.createAlias("s.pacienteServico", "p");
		if (anoInicio == anoFinal){
			criteria.add(Restrictions.eq("anoVencimento", anoFinal));
			criteria.add(Restrictions.between("mesVencimento", mesInicio, mesFinal));
		}else if(anoInicio < anoFinal){
			criteria.add(Restrictions.or(
							Restrictions.and(Restrictions.eq("anoVencimento", anoInicio),Restrictions.between("mesVencimento", mesInicio,12)),
							Restrictions.and(Restrictions.eq("anoVencimento", anoFinal), Restrictions.between("mesVencimento", 1, mesFinal))));			
		   
		}
		if(!StringUtilsOdontosis.isVazia(nomePaciente)){
			criteria.add(Restrictions.or(Restrictions.like("p.nome", nomePaciente, MatchMode.ANYWHERE), Restrictions.eq("p.numeroPasta", nomePaciente)));
		}
		if(paciente != null){
			criteria.add(Restrictions.eq("s.pacienteServico", paciente));
		}
		criteria.add(Restrictions.eq("ativo", true));
		criteria.addOrder(Order.asc("anoVencimento"));
		criteria.addOrder(Order.asc("mesVencimento"));
		criteria.addOrder(Order.asc("p.nome"));
		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		return criteria.list();
	}
	
	@SuppressWarnings("unchecked")
	public Collection<Pagamento> buscarPagamentosPorDataEPaciente(Integer ano,Integer mesInicial, Integer mesFinal, Long pacienteId){
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		session.beginTransaction();
		Transaction transaction = session.beginTransaction();
		String hql = "from Pagamento p where ativo = true and pago = false ";
		if(ano != null ){
			hql += " and anoVencimento = :ano ";
		}
		if(mesInicial != null && mesFinal != null && ano != null){
			hql += " and mesVencimento between :mesInicial and :mesFinal ";
		}
		if(pacienteId != null){
			hql += " and p.servico.pacienteServico.id = :pacienteId ";
		}
		
		hql += " and pago = false ";
		
		hql += " order by anoVencimento, mesVencimento ";
		
		Query query = getSession().createQuery(hql);
		
		if(ano != null ){
			query.setParameter("ano", ano);
		}
		if(mesInicial != null && mesFinal != null && ano != null){
			query.setParameter("mesInicial", mesInicial);
			query.setParameter("mesFinal", mesFinal);
		}
		if(pacienteId != null){
			query.setParameter("pacienteId", pacienteId);
		}
		
		List lista = query.list();
		transaction.commit();
		return lista;
		
//		Criteria criteria = session.createCriteria(Pagamento.class);
//		criteria.createAlias("servico", "s");
//		criteria.createAlias("s.pacienteServico", "p");
//		if(ano != null ){
//			criteria.add(Restrictions.eq("anoVencimento", ano));
//		}
//		if(mesInicial != null && mesFinal != null && ano != null){
//			criteria.add(Restrictions.between("mesVencimento", mesInicial, mesFinal));
//		}
//		if(pacienteId != null){
//			criteria.add(Restrictions.eq("p.id", pacienteId));
//		}
//		criteria.add(Restrictions.eq("pago", false));
//		criteria.add(Restrictions.eq("ativo", true));
//		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
//		return criteria.list();
	}
	
	@SuppressWarnings("unchecked")
	public Collection<Pagamento> buscarPagamentoPorServico(Servico servico){
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		Criteria criteria = session.createCriteria(Pagamento.class);
		criteria.add(Restrictions.eq("servico", servico));
		criteria.add(Restrictions.eq("ativo", true));
		return criteria.list();
	}
	
	public Integer numeroParcelas(Pagamento pagamento){
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		String sql = "select count(*) from Pagamento p where p.servico = :servico and p.ativo = true ";
		Query query = session.createQuery(sql);
		query.setParameter("servico", pagamento.getServico());
		Integer retorno = Integer.parseInt(((Long) query.uniqueResult()).toString());
		return retorno;
	}
	
	@SuppressWarnings("unchecked")
	public Collection<Servico> buscarServicosAtivos(Paciente paciente){
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		Criteria criteria = session.createCriteria(Servico.class);
		criteria.add(Restrictions.eq("pacienteServico", paciente));
		criteria.add(Restrictions.eq("ativo", true));
		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		return criteria.list();
	}
	
	@SuppressWarnings("unchecked")
	public Pagamento buscarUltimaParcela(Servico servico){
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		String sql = "from Pagamento p " +
				" where p.servico = :servico " +
				" and ativo = 1 " +
				" order by p.anoVencimento desc, p.mesVencimento desc";
		Query query = session.createQuery(sql);
		query.setParameter("servico", servico);
		query.setMaxResults(1);
		List<Pagamento> pagamentos = query.list();
		return !pagamentos.isEmpty() ?pagamentos.get(0):null;
	}
	
	public Pagamento buscarUltimaParcelaNaoPaga(Servico servico, int anoPagamento, int mesPagamento){
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		String sql = "from Pagamento p " +
				"where p.servico = :servico " +
				"  and p.pago = false" +
				" and p.ativo = true " +
				" and (p.anoVencimento < " + anoPagamento + " or (p.anoVencimento = "+anoPagamento+" and p.mesVencimento < "+mesPagamento+" )  )" +
				" order by p.anoVencimento desc, p.mesVencimento desc";
		Query query = session.createQuery(sql);
		query.setParameter("servico", servico);
		query.setMaxResults(1);
		List<Pagamento> pagamentos = query.list();
		return !pagamentos.isEmpty() ?pagamentos.get(0):null;
	}
	
	@SuppressWarnings("unchecked")
	public Collection<Pagamento> buscarMaiorVencimento(Paciente paciente){
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		String sql=  "select "+
	      "  this_.*  "+
	    " from "+
	      "  pagamento this_ "+
	    "inner join "+
	    "    servico s1_ "+
	    "        on this_.servico=s1_.id "+
	    "inner join "+
	    "    paciente p2_ "+
	    "        on s1_.paciente=p2_.id "+
	    "where "+
	    "    s1_.tipo = :tipo "+
	    "    and  mesVencimento = ( "+
	    "        select "+
	    "            max(mesVencimento) "+
	    "        from "+
	    "            pagamento p "+
	    "        inner join "+
	    "            servico s "+
	    "                on s.id = p.servico "+
	    "        where "+
	    "            s.paciente = :pacienteId "+
	    "            and s.tipo = :tipo " +
	    "			 and s.ativo = 1 "+
	    "			 and p.ativo = 1 "+
	    "            and anoVencimento = ( "+
	    "                select "+
	    "                    max(anoVencimento) "+
	    "                from "+
	    "                    pagamento p "+
	    "                inner join "+
	    "                    servico s "+
	    "                        on s.id = p.servico "+
	    "                where "+
	    "                    s.paciente = :pacienteId "+
	    "                    and s.tipo = :tipo " +
	    "					and s.ativo = 1  	" +
	    "					and p.ativo = 1     "+
	    "            ) "+
	    "        ) "+
	    "        and s1_.paciente = :pacienteId " +
	    "        and s1_.ativo = 1 " +
	    "        and this_.ativo = 1 " +
	    "		and p2_.ativo = 1";
		
		Query query = session.createSQLQuery(sql);
		query.setParameter("pacienteId", paciente.getId());
		query.setParameter("tipo", "3");
		
		
		return (Collection<Pagamento>) query.list();
		
	}
	
	
	public Integer buscarNumeroPrestacoesGeradas(){
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		Query query = session.createSQLQuery("select numeroParcelas from parametros where id = 1");
		return (Integer) query.uniqueResult();
	}
	
	public Collection<Pagamento> buscarParcelasIsentasPorPeriodo(Date inicio, Date fim , Paciente paciente, String nomePaciente) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(inicio);
		int mesInicio =  calendar.get(Calendar.MONTH) + 1;
		int anoInicio = calendar.get(Calendar.YEAR);
		calendar.setTime(fim);
		int mesFinal =  calendar.get(Calendar.MONTH) + 1;
		int anoFinal = calendar.get(Calendar.YEAR);
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		Criteria criteria = session.createCriteria(Pagamento.class);
		criteria.createAlias("servico", "s");
		criteria.createAlias("s.pacienteServico", "p");
		if (anoInicio == anoFinal){
			criteria.add(Restrictions.eq("anoVencimento", anoFinal));
			criteria.add(Restrictions.between("mesVencimento", mesInicio, mesFinal));
		}else if(anoInicio < anoFinal){
			criteria.add(Restrictions.or(
							Restrictions.and(Restrictions.eq("anoVencimento", anoInicio),Restrictions.between("mesVencimento", mesInicio,12)),
							Restrictions.and(Restrictions.eq("anoVencimento", anoFinal), Restrictions.between("mesVencimento", 1, mesFinal))));			
		   
		}
		if(!StringUtilsOdontosis.isVazia(nomePaciente)){
			criteria.add(Restrictions.or(Restrictions.like("p.nome", nomePaciente, MatchMode.ANYWHERE), Restrictions.eq("p.numeroPasta", nomePaciente)));
		}
		if(paciente != null){
			criteria.add(Restrictions.eq("s.pacienteServico", paciente));
		}
		criteria.add(Restrictions.eq("pago", true));
		criteria.add(Restrictions.not(Restrictions.eq("valor", 0.0 )));
		criteria.add(Restrictions.eq("ativo", true));
		criteria.addOrder(Order.asc("anoVencimento"));
		criteria.addOrder(Order.asc("mesVencimento"));
		criteria.addOrder(Order.asc("p.nome"));
		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		return criteria.list();
	}
	
	public List<Pagamento> buscarPagamentosParaAumento() {
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		String hql =
			" from Pagamento p " +
			" where p.pago = 0 and p.ativo = true " +
			" and (p.anoVencimento > :anoAtual or (p.mesVencimento >= :mesAtual and p.anoVencimento = :anoAtual)) " +
			" and (p.servico.anoVencimentoPrimeiraParcela < :anoPassado or (p.servico.mesVencimentoPrimeiraParcela <= :mesPassado and p.servico.anoVencimentoPrimeiraParcela = :anoPassado ))";
			
			
/*			
			SELECT p.id,p.valor,mesVencimento,anoVencimento,s.id,s.anoVencimentoPrimeiraParcela, s.mesVencimentoPrimeiraParcela FROM pagamento p
			INNER JOIN servico s ON s.id = p.servico
			WHERE p.pago = 0 AND p.ativo = 1 
			AND (p.anoVencimento > 2010 OR ( p.mesVencimento >= 2 AND p.anoVencimento = 2010))
			AND (s.anoVencimentoPrimeiraParcela < 2009 OR ( s.mesVencimentoPrimeiraParcela <= 2 AND s.anoVencimentoPrimeiraParcela = 2009))
	*/		
		
		Calendar atual = Calendar.getInstance();
		Calendar passada = Calendar.getInstance();
		passada.add(Calendar.MONTH, -11);
		
		
			
		Query query = session.createQuery(hql);
		query.setParameter("anoAtual", atual.get(Calendar.YEAR));
		query.setParameter("mesAtual", atual.get(Calendar.MONTH) + 1);
		query.setParameter("anoPassado", passada.get(Calendar.YEAR));
		query.setParameter("mesPassado", passada.get(Calendar.MONTH) + 1);
		return query.list();
	}
	
	public List<Object[]> buscarVariaveisAumento() {
		HibernateUtil.closeSession();
		Session session = HibernateUtil.currentSession();
		session.clear();
		String sql = " SELECT antigo_valor,novo_valor FROM aumento_parcela ";
		Query query = session.createSQLQuery(sql);
		return query.list();
	}
}
